#pragma once
#include <glm/glm.hpp>
#include <iostream>
#include <memory>
#include <vector>
namespace Umikaze::Core {

class Object;
class Camera;
class RenderTarget;
class Texture;
class Buffer;

enum TargetBuffer { COLOR_BUFFER = 1, DEPTH_BUFFER = 1 << 1 };

class RenderContext {
public:
  void setCameraProperties(const std::shared_ptr<Camera> &camera);

  void setCameraProperties(const std::unique_ptr<Camera> &camera);

  std::shared_ptr<Buffer> getCameraData();

  void setViewAndProjectionMatrix(const glm::mat4 &view,
                                  const glm::mat4 &projection);

  void setRenderTarget(const std::shared_ptr<RenderTarget> &renderTarget);

  glm::mat4 getViewMatrix() const;

  glm::mat4 getProjMatrix() const;

  glm::vec3 getCameraPosition() const;

  void drawMotionVector(const std::vector<std::shared_ptr<Object>> &objects,
                        const glm::mat4 &viewMatrix,
                        const glm::mat4 &projMatrix);

  void drawNormal();

  void draw(const std::vector<std::shared_ptr<Object>> &objects);

  void drawSkyBox(const std::shared_ptr<Texture> &texture);

  void drawDepth(const std::vector<std::shared_ptr<Object>> &objects);

  void drawShadow(const std::vector<std::shared_ptr<Object>> &objects,
                  const glm::mat4 &lightSPaceMatrix);

  void drawShadowCascade(const std::vector<std::shared_ptr<Object>> &object,
                         const std::shared_ptr<Buffer> &lightSpaceMatrices,
                         uint32_t matrixCount);

  void setDepthTest(bool enable);

  void setClearColor(float r, float g, float b, float a);

  void setCullFace(bool enable);

  // todo
  void setCullFaceMode(uint32_t mode);

  void setStencilTest(bool enable);

  void setClearBuffer(uint32_t bufferBit);

  struct CameraData {
    glm::mat4 _viewMatrix;
    glm::mat4 _projectionMatrix;
    glm::vec3 _cameraPosition;
  } _cameraData;

  std::shared_ptr<Buffer> _cameraBuffer;

  uint32_t _lightDataUbo = 0;
  uint32_t _cameraDataUbo = 0;

  std::shared_ptr<RenderTarget> _renderTarget;

  float _r, _g, _b, _a;
  uint32_t _clearBit;
  bool _enableDepthTest = false;
  bool _enableCullFace = false;
  bool _enableStencilTest = false;
  uint32_t _cullMode;

private:
  void bindDefaultFbo() const;
};

} // namespace Umikaze::Core
